mod state;
mod context;
mod mesh;
mod instance;
mod texture;
mod uniform;
mod camera;
mod model_loader;
mod control;

mod voxel;

use winit::{event_loop::{EventLoop, ControlFlow}, window::WindowBuilder, event::{Event, WindowEvent, KeyboardInput, ElementState, VirtualKeyCode}};

pub async fn run() {
    env_logger::init();
    let event_loop = EventLoop::new();
    let window = WindowBuilder::new().build(&event_loop).unwrap();

    let mut state: Box<dyn state::State> = if std::env::var("VOXEL").is_ok() {
        Box::new(voxel::renderer::Renderer::new(window).await)
    } else {
        Box::new(state::MyState::new(window).await)
    };

    event_loop.run(move |event, _, control_flow| match event {
        Event::WindowEvent {
            ref event,
            window_id
        } if window_id == state.get_window().id() => if !state.input(event) {
            match event {
                WindowEvent::CloseRequested |
                WindowEvent::KeyboardInput {
                    input: KeyboardInput {
                        state: ElementState::Pressed,
                        virtual_keycode: Some(VirtualKeyCode::Escape),
                        ..
                    },
                    ..
                } =>
                    *control_flow = ControlFlow::Exit,
                WindowEvent::Resized(physical_size) =>
                    state.resize(*physical_size),
                WindowEvent::ScaleFactorChanged { new_inner_size, .. } =>
                    state.resize(**new_inner_size),
                _ => {}
            }
        }
        Event::RedrawRequested(
            window_id
        ) if window_id == state.get_window().id() => {
            state.update();
            match state.render() {
                Ok(_) => {}
                Err(wgpu::SurfaceError::Lost) =>
                    state.reconfigure(),
                Err(wgpu::SurfaceError::OutOfMemory) =>
                    *control_flow = ControlFlow::Exit,
                Err(e) => eprintln!("{:?}", e)
            }
        }
        Event::MainEventsCleared => {
            state.get_window().request_redraw();
        }
        _ => {}
    });
}
